package cn.mazexal.examapi.controller.notify;

import cn.hutool.core.util.IdUtil;
import cn.mazexal.examapi.common.anno.PermitGuest;
import cn.mazexal.examapi.dataware.FinNotificationLogMapper;
import cn.mazexal.examapi.models.bo.PayNotify;
import cn.mazexal.examapi.models.db.FinNotificationLogDO;
import cn.mazexal.examapi.models.db.FinOrderDO;
import cn.mazexal.examapi.models.enums.PayStatusEnum;
import cn.mazexal.examapi.models.form.AppleNotifyForm;
import cn.mazexal.examapi.models.redisKeys.RedisCommonKey;
import cn.mazexal.examapi.models.redisKeys.RedisOrderKey;
import cn.mazexal.examapi.services.OrderService;
import cn.mazexal.examapi.services.RedisService;
import cn.mazexal.examapi.services.provider.AppleProvider;
import com.alibaba.fastjson2.JSON;
import com.apple.itunes.storekit.model.*;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

import static cn.mazexal.examapi.models.enums.FinNotificationUrlEnum.APPLE_NOTIFY;

/**
 * @author: Mazexal
 * Date: 2025/6/30
 */
@RestController
@Tag(name = "notify", description = "回调")
@RequestMapping("/notify/apple")
@Slf4j
public class AppleNotifyController {

    @Resource
    private OrderService orderService;

    @Resource
    private AppleProvider appleProvider;

    @Resource
    private RedisService redisService;

    @Resource
    private FinNotificationLogMapper finNotificationLogMapper;

    @PermitGuest
    @RequestMapping("/appleNotify")
    public String appleNotify(@RequestBody AppleNotifyForm appleNotifyForm) {
        return exec(appleNotifyForm.getSignedPayload());
    }

    // 这里需要先保存信息, 然后处理
    private String exec(String signedPayload) {
        try {
            log.info("apple info:{}", signedPayload);
            if (StringUtils.isEmpty(signedPayload)) {
                return "fail";
            }
            ResponseBodyV2DecodedPayload payload = appleProvider.verifyNotification(signedPayload);
            if (payload == null) {
                return "fail";
            }
            Long now = System.currentTimeMillis();
            log.info("apple decodeInfo:{}", payload);
            String notificationUUID = payload.getNotificationUUID();
            String appleyNotifyKey = RedisOrderKey.getAppleyNotifyKey(notificationUUID);
            if (!redisService.tryLock(appleyNotifyKey, RedisCommonKey.keyValue, 5, TimeUnit.SECONDS)) {
                return "fail";
            }
            // 这里要做幂等处理, 通过notifyLog的UUID
            FinNotificationLogDO finPayAppleNotifyHis = orderService.getFinPayAppleNotifyHis(notificationUUID);

            if (finPayAppleNotifyHis != null && "SUCCESS".equals(finPayAppleNotifyHis.getProcessResult())) {
                return "{}";
            }

            NotificationTypeV2 notificationType = payload.getNotificationType();
            Subtype subtype = payload.getSubtype();

            String singedTransactionInfo = payload.getData().getSignedTransactionInfo();
            if (StringUtils.isBlank(singedTransactionInfo)) {
                log.warn("appleNotify:交易信息为空");
                return "fail";
            }
            JWSTransactionDecodedPayload transaction = appleProvider.verifyTransaction(singedTransactionInfo);

            // orderUUID就是之前服务端生成的给客户端的UUID, 可以通过这个UUID查询订单
            String orderUUID = transaction.getAppAccountToken().toString();

            FinOrderDO order = orderService.getAppleOrderByUUID(orderUUID);

            Long orderId = 0L;
            if (order != null) {
                orderId = order.getId();
            }
            // 添加记录
            Long notifyLogId = addFinPayAppleNotifyHis(payload, notificationUUID, orderId);
            // 这里开始正式处理
            switch (notificationType) {
                case ONE_TIME_CHARGE:
                    // 因为直接在applePayVerify里操作过了, 不用等回调处理这些, 所以直接返回成功
                    finNotificationLogMapper.updateLogRes(notifyLogId, "SUCCESS", now);
                    break;
                case SUBSCRIBED: // 订阅
                case DID_CHANGE_RENEWAL_PREF:
                    if (notificationType == NotificationTypeV2.DID_CHANGE_RENEWAL_PREF && subtype == Subtype.DOWNGRADE) {
                        // 如果是降级的话, 不做处理. 等待过期回调续订就行
                        finNotificationLogMapper.updateLogRes(notifyLogId, "SUCCESS", now);
                        return "{}";
                    }
                    PayNotify payNotify = new PayNotify();
                    payNotify.setPayId(orderId);
                    payNotify.setBuyerId(String.valueOf(order.getUserId()));
                    payNotify.setBuyerAccount(transaction.getOriginalTransactionId());
                    payNotify.setSellerId(transaction.getBundleId());
                    payNotify.setSellerAccount(transaction.getBundleId());
                    payNotify.setTotalAmount(new BigDecimal(transaction.getPrice()).multiply(BigDecimal.valueOf(transaction.getQuantity())).divide(BigDecimal.valueOf(100)));
                    payNotify.setNotifyId(notificationUUID);
                    payNotify.setNotifyLogId(notifyLogId);
                    // 处理订阅
                    orderService.handlePayNotify(payNotify);
                    break;

                case DID_RENEW:
                    //// 内购,内购是没有回调的 CONSUMABLE
                    String signedRenewalInfo = payload.getData().getSignedRenewalInfo();
                    JWSRenewalInfoDecodedPayload renewalInfo = appleProvider.verifyRenewalInfo(signedRenewalInfo);
//                    if (notificationType == NotificationTypeV2.ONE_TIME_CHARGE) {
//                        renewalInfo = appleProvider.verifyRenewalInfo(payload.getData().getSignedTransactionInfo());
//                    } else {
//                        renewalInfo = appleProvider.verifyRenewalInfo(signedRenewalInfo);
//                    }
                    renewalInfo.getAutoRenewStatus();// 是否续订 1 为续订 0 为取消订阅
                    orderService.addResumeOrder(renewalInfo, transaction, notifyLogId);
                    break;
                case REFUND: // 退款
                    // 移除VIP权益相应的天数.
                    // 通过异步通知客户端, 移除VIP权益? (或者服务端已经知道了, 调用需要VIP的服务的时候, 返回已过期)
                    // 将原来的订单设置为已退款
                    orderService.handleRefund(order, transaction, notifyLogId);
                    break;
                // 需要成功
                default:
                    log.warn("未知的appleNotify:{}", notificationType);
                    break;
            }
            redisService.releaseLock(appleyNotifyKey, RedisCommonKey.keyValue);
        } catch (Exception e) {
            log.error("appleNotify", e);
            return "failerror";
        }
        return "{}";
    }


    private Long addFinPayAppleNotifyHis(ResponseBodyV2DecodedPayload payload, String notificationUUID, Long orderId) {
        Long now = System.currentTimeMillis();
        Long id = IdUtil.getSnowflakeNextId();
        FinNotificationLogDO finNotificationLogDO = new FinNotificationLogDO();
        finNotificationLogDO.setId(id);
        finNotificationLogDO.setLogUrl(APPLE_NOTIFY.getUrl());
        finNotificationLogDO.setEnviroment(payload.getData().getEnvironment().getValue());
        finNotificationLogDO.setNotificationId(notificationUUID);
        finNotificationLogDO.setNotificationData(JSON.toJSONString(payload));
        finNotificationLogDO.setNotificationId(notificationUUID);
        finNotificationLogDO.setRelatedOrderNo(String.valueOf(orderId));
        finNotificationLogDO.setIsProcessed(0);
        finNotificationLogDO.setExtraInfo(JSON.toJSONString(payload));
        finNotificationLogDO.setProcessResult("");
        finNotificationLogDO.setCreatTime(now);
        finNotificationLogDO.setUpdatedTime(now);
        orderService.addFinNotification(finNotificationLogDO);
        return id;
    }
}
